package com.steellee.leeexcel.util;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.util.BooleanUtils;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.steellee.leeexcel.dto.MetaCellStyle;
import com.steellee.leeexcel.dto.MetaDataOperate;
import com.steellee.leeexcel.exception.BusinessException;
import com.steellee.leeexcel.exception.MsgCode;
import org.apache.poi.ss.usermodel.*;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Bauthor steellee
 *
 * @date 2023-3-1
 * 设置 Cellstyle样式
 */
public class CellStyleUtil {
    private static final String SINGLE = "SINGLE";
    private static final String RANGE = "RANGE";
    private static final String GREATER = "GREATER";
    private static final String LESS = "LESS";
    private static final String EQUAL = "EQUAL";
    private static final String GREATER_EQUAL = "GREATER_EQUAL";
    private static final String LESS_EQUAL = "LESS_EQUAL";
    private static final String NOT_EQUAL = "NOT_EQUAL";
    private static final String CONTAIN = "CONTAIN";
    private static final String NO_CHECK = "NO_CHECK";

    /**
     * 通过反射获取ExcelProperty注解设置 index值
     *
     * @param clazz     返回对象名.class
     * @param fieldName 对象字段名
     * @return
     * @ throws Exception
     */
    public static Integer getCellColumn(Class clazz, String fieldName) throws Exception {

        //反射找到字段
        Field displayName = clazz.getDeclaredField(fieldName);

        //获取字段上的注解
        ExcelProperty annotation = displayName.getAnnotation(ExcelProperty.class);
        InvocationHandler h = Proxy.getInvocationHandler(annotation);

        // 获取 AnnotationInvocationHandler 的 memberValues 字段
        Field hField = h.getClass().getDeclaredField("memberValues");

        // 因为这个字段是 private final 修饰, 所以要打开权限
        hField.setAccessible(true);
        Map memberValues = (Map) hField.get(h);
        return (Integer) memberValues.get("index");
    }

    /**
     * 通过反射获取ExcelProperty注解设置 index值
     *
     * @param clazz     返回对象名.class
     * @param fieldName 对象字段名
     * @return
     * @ throws Exception
     */
    public static String getCellName(Class clazz, String fieldName) throws Exception {

        //反射找到字段
        Field displayName = clazz.getDeclaredField(fieldName);

        //获取字段上的注解
        ExcelProperty annotation = displayName.getAnnotation(ExcelProperty.class);
        InvocationHandler h = Proxy.getInvocationHandler(annotation);

        // 获取 AnnotationInvocationHandler 的 memberValues 字段
        Field hField = h.getClass().getDeclaredField("memberValues");

        // 因为这个字段是 private final 修饰,所以要打开权限
        hField.setAccessible(true);
        Map memberValues = (Map) hField.get(h);
        String[] str = (String[]) memberValues.get("value");
        return str[0];
    }

    /**
     * 提供默认样式-支持入参数据 Map传入或 对象传入
     *
     * @param context
     * @param headRows
     * @param isMap
     **/
    public static void setWriteCellStyle(CellWriteHandlerContext context, List<Integer> headRows, boolean isMap) {
        WriteCellData cellData = context.getFirstCellData();
        WriteCellStyle writeCellStyle;
        if (isMap) {
            writeCellStyle = new WriteCellStyle();
        } else {
            writeCellStyle = cellData.getWriteCellStyle();
            writeCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
            writeCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        }
        writeCellStyle.setBorderBottom(BorderStyle.THIN);
        writeCellStyle.setBorderLeft(BorderStyle.THIN);
        writeCellStyle.setBorderRight(BorderStyle.THIN);
        writeCellStyle.setBorderTop(BorderStyle.THIN);
        WriteFont writeFont = new WriteFont();
        writeFont.setFontName("宋体");
        if (BooleanUtils.isTrue(context.getHead()) || (!ObjectUtils.isEmpty(headRows)
                && headRows.contains(context.getCell().getRowIndex()))) {
            writeCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            writeCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            writeFont.setBold(true);
        }
        writeCellStyle.setWriteFont(writeFont);
        cellData.setWriteCellStyle(writeCellStyle);
    }

    /**
     * 入参数据对象类型-自定义样式复制
     * new WriteCellstyle 会冲掉数据对象注解属性，通过反射去遍历赋值可以保留注解属性
     * 反射获取dataCellStyle属性值,并反射赋值给writeCellStyle
     *
     * @param writeCellStyle
     * @param dataCellStyle
     */
    public static void copyValue(WriteCellStyle writeCellStyle, MetaCellStyle dataCellStyle) {
        try {
            Field[] fields = dataCellStyle.getClass().getSuperclass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                Field copyField = writeCellStyle.getClass().getDeclaredField(field.getName());
                if (null != field.get(dataCellStyle)) {
                    copyField.setAccessible(true);
                    copyField.set(writeCellStyle, field.get(dataCellStyle));
                }
            }
        } catch (Exception e) {
            throw new BusinessException("拷贝属性异常! ");
        }
    }

    public static List<Integer> getColumnList(MetaDataOperate operate) {
        if (SINGLE.equals(operate.getOperateType())) {
            if (ObjectUtils.isEmpty(operate.getColumnList())) {
                throw new BusinessException(MsgCode.COLUMN_NO_DATA.code, MsgCode.COLUMN_NO_DATA.msg);
            }
            return operate.getColumnList();
        } else if (RANGE.equals(operate.getOperateType())) {
            if (null == operate.getStartColumn() || null == operate.getEndColumn()) {
                throw new BusinessException(MsgCode.COLUMN_NO_START_END.code, MsgCode.COLUMN_NO_START_END.msg);
            }
            List<Integer> columnList = new ArrayList<>();
            for (int i = operate.getStartColumn(); i <= operate.getEndColumn(); i++) {
                columnList.add(i);
            }
            return columnList;
        } else {
            return new ArrayList<>();
        }
    }

    public static List<Integer> getMapRowList(int size, List<List<Object>> mapList, MetaDataOperate operate) {
        List<Integer> rowList = new ArrayList<>();
        Map<String, Object> checkBasis = operate.getCheckBasis();
        if (NO_CHECK.equals(checkBasis.get("basis").toString())) {
            for (int i = 0; i < mapList.size(); i++) {
                rowList.add(i + size);
            }
        } else {
            String value = checkBasis.get("value").toString();
            for (int i = 0; i < mapList.size(); i++) {
                String checkValue = mapList.get(i).get(Integer.valueOf(checkBasis.get("keyIndex").toString())).toString();
                getRowList(rowList, i, size, value, checkValue, checkBasis);
            }
        }
        return rowList;
    }

    public static List<Integer> getObjRowList(int size, List dataList, MetaDataOperate operate) {
        List<Integer> rowList = new ArrayList<>();
        Map<String, Object> checkBasis = operate.getCheckBasis();
        if (NO_CHECK.equals(checkBasis.get("basis").toString())) {
            for (int i = 0; i < dataList.size(); i++) {
                rowList.add(i + size);
            }
        } else {
            String value = checkBasis.get("value").toString();
            for (int i = 0; i < dataList.size(); i++) {
                String checkValue = "";
                Class clazz = dataList.get(i).getClass();
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    if (field.getName().equals(checkBasis.get("key").toString())) {
                        try {
                            checkValue = field.get(dataList.get(i)).toString();
                            getRowList(rowList, i, size, value, checkValue, checkBasis);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                        break;
                    }
                }
            }
        }
        return rowList;
    }

    private static void getRowList(List<Integer> rowList, int i, int size, String value, String checkValue, Map<String, Object> checkBasis) {
        if (GREATER.equals(checkBasis.get("basis").toString()) && checkValue.compareTo(value) > 0) {
            rowList.add(i + size);
            return;
        }
        if (LESS.equals(checkBasis.get("basis").toString()) && checkValue.compareTo(value) < 0) {
            rowList.add(i + size);
            return;
        }
        if (EQUAL.equals(checkBasis.get("basis").toString()) && checkValue.compareTo(value) == 0) {
            rowList.add(i + size);
            return;
        }
        if (GREATER_EQUAL.equals(checkBasis.get("basis").toString()) && checkValue.compareTo(value) >= 0) {
            rowList.add(i + size);
            return;
        }
        if (LESS_EQUAL.equals(checkBasis.get("basis").toString()) && checkValue.compareTo(value) <= 0) {
            rowList.add(i + size);
            return;
        }
        if (NOT_EQUAL.equals(checkBasis.get("basis").toString()) && checkValue.compareTo(value) != 0) {
            rowList.add(i + size);
            return;
        }
        if (CONTAIN.equals(checkBasis.get("basis").toString()) && checkValue.contains(value)) {
            rowList.add(i + size);
            return;
        }
        if (NO_CHECK.equals(checkBasis.get("basis").toString())) {
            rowList.add(i + size);
            return;
        }
    }
}
